<?php
declare(strict_types=1);

namespace Modules\Production\Service;


use App\Services\InventoryService;
use App\Services\KingDeeService;
use App\Services\UnitService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Modules\Base\Repository\BoxTurnoverRepository;
use Modules\Inventory\Repository\InventoryRepository;
use Modules\Production\Models\PickOrder;
use Modules\Production\Models\PickOrderDetail;
use Modules\Production\Models\StockTaskScan;
use Modules\Production\Repository\PickOrderRepository;
use Modules\Production\Repository\ProductionOrderDetailRepository;
use Modules\Production\Repository\ProductionOrderRepository;
use Modules\Production\Repository\ProductionOrderStockUserRepository;
use Modules\Production\Repository\StockTaskScanRepository;
use App\Enums\InvTransDocType;
use App\Enums\ProductionOrderBackStatus;
use Modules\Warehouse\Models\Storagelocation;


class TaskScanService
{

    /**
     * 备货任务分配人员
     * @param $postData
     * @throws \Exception
     */
    static public function bindOperator($postData){
        return (new ProductionOrderStockUserRepository())->save(Auth::guard(getGuardName())->id(),$postData['order_ids'],$postData['uids']);
    }

    /**
     * 备货任务扫描
     * @param $postData
     * @return bool
     * @throws \Throwable
     */
    static public function materialScan($postData){

        try {

            $toLotNum = isset($postData['to_lot_num']) ? $postData['to_lot_num'] : '';

            DB::beginTransaction();

            //库存信息
            $invInfo = InventoryRepository::getById($postData['inv_id']);

            if( $invInfo->qty < ($invInfo->lock_qty + $invInfo->assign_qty + $postData['qty']) ){
                throw new \Exception('库存不足');
            }

            //生产工单信息
            $production = ProductionOrderRepository::getOrderById($postData['order_id']);

            //生产工单行信息
            $productionDetail = ProductionOrderDetailRepository::findDetailBy($postData['order_id'],$postData['material_no']);
            if(!$productionDetail){
                throw new \Exception('当前工单不存在扫描的物料');
            }

            if($productionDetail->back_status == 2){
                throw new \Exception('当前物料已完成备货');
            }

            //1、修改库存分配数量
            InventoryService::assignInvById(
                $production->id,
                $production->fbillno,
                InvTransDocType::PRODUCTION_WORK_ORDERS->value,
                $postData['inv_id'],
                $postData['qty']
            );
            if(InventoryRepository::hasQtyByLotnum($postData['lot_num']) && empty($postData['to_lot_num'])){
                throw new \Exception("箱号【{$postData['lot_num']}】物料未全部领完，必须扫描容器号");
            }

            //2、记录扫描数据
            StockTaskScanRepository::save([
                'order_id'      => $production->id,
                'material_no'   => $postData['material_no'],
                'qty'           => $postData['qty'],
                'lot_num'       => $postData['lot_num'],
                'location'      => $invInfo->location,
                'to_lot_num'    => $toLotNum,
                'inv_id'        => $invInfo->id,
            ]);

            //3、绑定新箱号处理
            if(!empty($toLotNum)){

                //箱号存在周转记录，并且绑定的不是当前订单，先清空周转记录
                $turnover = BoxTurnoverRepository::getBoxTurnoverByLotnum($toLotNum);
                if($turnover && $turnover->order_id != $postData['order_id']){
                    BoxTurnoverRepository::deleteByLotnum($toLotNum);
                }

                //保存箱号周转记录
                BoxTurnoverRepository::save([
                    'order_id'      => $postData['order_id'],
                    'doc_type'      => InvTransDocType::PRODUCTION_WORK_ORDERS->value,
                    'material_no'   => $postData['material_no'],
                    'from_lotnum'   => $postData['lot_num'],
                    'lot_num'       => $toLotNum,
                    'qty'           => $postData['qty'],
                    'location'      => $invInfo->location,
                ]);

            }

            Db::commit();
            return true;

        }catch (\Exception $e){
            Db::rollBack();
            throw $e;
        }

    }

    /**
     * 删除扫描数据
     * @param $scanId
     */
    static public function deleteScan($scanId){

        $scanItem = StockTaskScan::find($scanId);
        if(!$scanItem){
            throw new \Exception('扫描详情id不存在');
        }

        if($scanItem->push_kingdee != 0){
            throw new \Exception('删除失败，已推送金蝶');
        }

        try{

            DB::beginTransaction();

            $productionOrder = ProductionOrderRepository::getOrderById($scanItem->order_id);

            //释放分配库存
            InventoryService::releaseAssign(
                $productionOrder->id,
                $productionOrder->fbillno,
                InvTransDocType::PRODUCTION_WORK_ORDERS->value,
                $scanItem->inv_id,
                $scanItem->qty
            );

            //删除扫描记录
            $scanItem->delete();

            DB::commit();

            return true;

        }catch (\Exception $e){
            DB::rollBack();

            throw $e;

        }

    }

    /**
     * 根据库位代码获取所属仓库代码
     * @param $location
     * @return string
     */
    static public function getWmsCodeByLocation($location){
        $wmsInfo = Storagelocation::with('wms')->where('warehousecode',$location)->first();
        return $wmsInfo ? $wmsInfo->wms->fnumber : '';
    }

    /**
     * 备货任务提交
     * @param $postData
     */
    static public function scanSubmit($postData){

        //生产工单信息
        $productionOrder = ProductionOrderRepository::getOrderById($postData['production_id']);

        if($productionOrder->back_status == ProductionOrderBackStatus::ALREADY_BACK->value){
            throw new \Exception('当前工单已全部领料');
        }

        //查询扫描记录
        $scanLog = StockTaskScanRepository::getListNoKingdeeByProductionId($postData['production_id']);
        if($scanLog->isEmpty()){
            throw new \Exception('暂无未领料数据');
        }

        try {

            DB::beginTransaction();

            //生产领料单表头保存
            $pickOrder = self::savePickOrder($productionOrder);

            $kingdeeItem = [];
            //生产领料单子项
            $pickItem = [];
            foreach ($scanLog as $scanObj){
                //扣减库存
                $invInfo = InventoryService::decInventoryByAssign(
                    $pickOrder['docno'],
                    $pickOrder['id'],
                    InvTransDocType::PRODUCTION_PICKING->value,
                    $scanObj->inv_id,
                    $scanObj->qty
                );

                //生产工单子项
                $productionDetail = ProductionOrderDetailRepository::findDetailBy($productionOrder->id,$scanObj->material_no);

                //金蝶推送状态
                StockTaskScanRepository::updateById($scanObj->id,['push_kingdee' => 1]);

                //回写领料数量、备货状态
                //ProductionOrderDetailRepository::IncById($productionDetail->id,'fpickedqty',$scanObj->qty);
                //ProductionOrderDetailRepository::IncById($productionDetail->id,'fsolidcollarqty',$scanObj->qty);
                ProductionOrderDetailRepository::updateById($productionDetail->id,[
                    'fpickedqty'        => DB::raw("fpickedqty + {$scanObj->qty}"),
                    'fsolidcollarqty'   => DB::raw("fsolidcollarqty + {$scanObj->qty}"),
                    'back_status'       => ($productionDetail->fpickedqty + $scanObj->qty) >= $productionDetail->fmustqty ? 2 : 1,
                ]);

                $wmsCode = self::getWmsCodeByLocation($scanObj->location);

                $pickItem[] = [
                    'production_no' => $productionOrder->fbillno,
                    'fid'           => $productionOrder->fid,
                    'fentryid'      => $productionDetail->fentryid,
                    'location'      => $scanObj->location,
                    'order_id'      => $pickOrder['id'],
                    'material_no'   => $scanObj->material_no,
                    'qty'           => $scanObj->qty,
                    'wms_code'      => $wmsCode,
                    'lot_num'       => !empty($scanObj->to_lot_num) ? $scanObj->to_lot_num : $scanObj->lot_num,
                    'unit'          => $productionDetail->funitid1_number,
                    'row_num'       => $productionDetail->fseq,
                    'supplier_code' => $invInfo->supplier_code,
                    'creator_id'    => Auth::guard(getGuardName())->id(),
                    'created_at'    => time(),
                    'updated_at'    => time(),
                ];


            }

            //保存生产领料单子项
            (new PickOrderDetail())->insert($pickItem);

            //修改生产工单备货状态
            ProductionOrderRepository::checkStockStatus($productionOrder->id);

            //提交领料单到金蝶
            self::pushProductionToKingdee($pickOrder,$productionOrder->fmotype,$postData['time']);

            Db::commit();

        }catch (\Exception $e){

            Db::rollBack();

            if(mb_strpos($e->getMessage(),'更新库存出现异常情况，更新库存不成功') !== false){
                throw new \Exception('提交失败，请检查预留');
            }

            throw $e;
        }

    }

    /**
     * 推送领料单到金蝶
     * @param $productionOrder
     */
    static public function pushProductionToKingdee($pickOrder,$orderType,$times = null){

        $type = $orderType == '普通委外订单' ? 'SUB_PickMtrl' : 'PRD_PickMtrl';

        $order = [
            'FBILLTYPEID'   => $type,
            'FBILLNO'       => $pickOrder['docno'],
            'FORGID'        => $pickOrder['org_code'],
            'FDATE'         => $times ?: date('Y-m-d H:i:s'),
        ];

        $item = [];
        //汇总领料单子项数据
        $pickOrderDetail = PickOrderRepository::getGroupByListByOrderId($pickOrder['id']);
        foreach ($pickOrderDetail as $val){
            $item[] = [
                'FOwnerTypeId'          => $pickOrder['cargo_type'],
                'FOwnerId'              => $pickOrder['cargo_code'],
                'FSRCBILLNO'            => $val->production_no,
                'FSRCID'                => $val->fid,
                'FSRCSEQ'               => $val->row_num,
                'FSRCENTRYID'           => $val->fentryid,
                'FMATERIALID'           => $val->material_no,
                'FUNITID'               => $val->unit,
                'FQTY'                  => $val->qty,
                'FSTOCKID'              => $val->wms_code,
                //'FDESTSTOCKID' => '仓库（传编码）',
                'FGIVEAWAY'             => 'false',
            ];
        }

        $order['FEntity'] = $item;

        return (new KingDeeService())->form('TVJB_DJWMSDJ')->invokeSave($order);

    }

    /**
     * 生产领料单表头入库
     * @param $productionOrder
     * @return mixed
     */
    static public function savePickOrder($productionOrder){

        $insertData = [
            'org_code'      => $productionOrder->fprdorgid_number,
            'cargo_type'    => $productionOrder->fownertypeidsety,
            'cargo_code'    => $productionOrder->fowneridsety_number,
            'docno'         => UnitService::createDocno('SCLL'),
            'producton_id'  => $productionOrder->id,
            'kingdee_status'=> 1,
            'production_no' => $productionOrder->fbillno,
        ];

        $pickId = (new PickOrder())->storeBy($insertData);

        return array_merge($insertData,['id'=>$pickId]);
    }

}
